/*
 * Javascript Agile Suite - JasFacTests
 * http://code.google.com/p/jasproject/
 *
 * Copyright (C) 2009 Luke Schafer
 * Licensed under MIT X11 license:
 * http://www.opensource.org/licenses/mit-license.php
 *
 *
 * Test JasFac
 * There is quite a bit of double up (e.g. testing .register
 * and .named when .register uses .named and vice-versa. 
 * This isn't totally illogical as if the tests fail, seeing
 * which ones failed will help narrow it down faster.
 */

Jas.Tests = Jas.Tests || {};

Jas.Tests.JasFac = {
	namespace : "Jas.Tests.JasFac",

	setup : function()
	{
		this.builder = new JasFac.Builder();
		this.container = new JasFac.Container();
	},
	
	testRegister : function()
	{
		// Register an instance.
		this.builder.register({method:function(){ return "_foo_"; }}).named("a1");
		this.builder.register({
			name : "a2",
			instance : {method:function(){ return "_foo_"; }}
		});

		// Register an expression.
		this.builder.register(function exp(c) { return c.resolve("a1"); }).named("b1");
		this.builder.register({
			name : "b2",
			expression : function exp(c) { return c.resolve("a2"); }
		});

		// Register a constructor.
		this.builder.register(function () { this.c = {}; }).named("c1");
		this.builder.register({
			name : "c2",
			constructor : function () { this.c = {}; }
		});

		this.builder.build(this.container);

		Assert.isNotNull(this.container.resolve("a1"));
		Assert.isNotNull(this.container.resolve("a2"));
		Assert.isNotNull(this.container.resolve("b1"));
		Assert.isNotNull(this.container.resolve("b2"));
		Assert.isNotNull(this.container.resolve("c1"));
		Assert.isNotNull(this.container.resolve("c2"));
	},

	testRegisterConstructor : function()
	{	
		this.builder.registerConstructor(function () { this.c = {}; }).named("a");
		this.builder.build(this.container);

		Assert.isNotNull(this.container.resolve("a"));
	},

	testRegisterExpression : function()
	{
		this.builder.register(function exp(c) { return {}; }).named("a1");
		this.builder.registerExpression(function exp(c) { return c.resolve("a1"); }).named("a");
		this.builder.build(this.container);

		Assert.isNotNull(this.container.resolve("a"));
	},

	testRegisterInstance : function()
	{
		this.builder.registerInstance({method:function(){ return "_foo_"; }}).named("a");
		this.builder.build(this.container);

		Assert.isNotNull(this.container.resolve("a"));
	},

	testRegisterConfig : function()
	{
		Assert.ignore();
	},

	testNamed : function()
	{
		this.builder.register({method:function(){ return "_foo_"; }}).named("foo");
		this.builder.build(this.container);
		var foo = this.container.resolve("foo");
		Assert.isNotNull(foo);
		Assert.areEqual("_foo_", foo.method());
	},

	testAs : function()
	{
		var stub = {};
		function Foo()
		{
			this.method = function() { return "_foo_"; }
		}
		function Bar()
		{
			this.method = function() { return "_bar_"; }
		}

		this.builder.register(Foo).as(stub);
		this.builder.register(Bar);
		this.builder.build(this.container);

		var foo = this.container.resolve(stub);
		var bar = this.container.resolve(Bar);

		Assert.isNotNull(foo);
		Assert.isNotNull(bar);
		Assert.areEqual("_foo_", foo.method());
		Assert.areEqual("_bar_", bar.method());
		Assert.isNull(this.container.resolveOptional(Foo));
	},

	testInjectProperties : function()
	{
		// Create and wrap bar type mock.
		function _bar() {}
		_bar.prototype.go = function(){};
		var Bar = JasMock.wrap(_bar);

		this.builder.register(new Bar()).as(Bar);
		this.builder.registerInstance({name:"fooey"}).named("foo");

		this.builder.register(function exp(c) { return {}; }).named("a").injectProperties({
			foo : "foo",
			bar : Bar,
			val : function exp(c) { return 7; }
		});

		this.builder.register({
			expression : function exp(c) { return {}; },
			name : "b",
			properties : {
				foo : "foo",
				bar : Bar,
				val : function exp(c) { return 7; }
			}
		});

		this.builder.build(this.container);

		var a = this.container.resolve("a");
		var b = this.container.resolve("b");
		a.bar.go();

		Assert.areEqual(a.foo, b.foo);
		Assert.areEqual("fooey", a.foo.name);
		Assert.areEqual(a.bar, b.bar);
		Assert.isTrue(a.bar.go.checkWasCalled());
		Assert.areEqual(7, a.val);
		Assert.areEqual(7, b.val);
	},

	testInjectArguments : function()
	{
		function FooBar(foo, bar, val1, val2)
		{ 
			this.foo = foo;
			this.bar = bar;
			this.val1 = val1 + 1;
			this.val2 = val2;
		};
		this.builder.register(FooBar).injectArguments({
			foo : "abc",
			val1 : 1
		}); 

		this.builder.register({method:function(){ return "_bar_"; }}).named("bar");
		this.builder.register({method:function(){ return "_val2_"; }}).named("val2");

		this.builder.build(this.container);

		var test = this.container.resolve(FooBar, {
			val1 : 2, //override
			val2 : function exp(c) { return c.resolve("val2"); }
		});

		Assert.areEqual(3, test.val1);
		Assert.areEqual("_val2_", test.val2.method());
		Assert.areEqual("abc", test.foo);
		Assert.areEqual("_bar_", test.bar.method());
	}
};